// (c) Copyright 2013-2014 Stephen Gold <sgold@sonic.net>
// Distributed under the terms of the GNU General Public License

/*
 This file is part of the Bats Game.

 The Bats Game is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by the
 Free Software Foundation, either version 3 of the License, or (at your
 option) any later version.

 The Bats Game is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.

 You should have received a copy of the GNU General Public License
 along with the Bats Game.  If not, see <http://www.gnu.org/licenses/>.
 */
package bats.indicator;

import bats.Assets;
import bats.scene.PointOfView;
import bats.scene.SceneControl;
import bats.scene.SceneNode;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import java.util.logging.Logger;
import jme3utilities.MySpatial;
import jme3utilities.math.MyVector3f;

/**
 * A scene control to update the location and appearance of the 3-D cursor
 * indicator in a scene.
 * <p>
 * The 3D cursor serves two functions: (1) as the insertion point, it marks the
 * location where new objects will be inserted and (2) when active, it provides
 * a target for aiming the POV in orbiting mode.
 * <p>
 * The cursor's color reflects whether it is active or not. It is enabled at
 * creation and activated during initialization.
 *
 * @author Stephen Gold <sgold@sonic.net>
 */
public class Cursor3DIndicator
        extends SceneControl {
    // *************************************************************************
    // constants

    /**
     * message logger for this class
     */
    final private static Logger logger =
            Logger.getLogger(Cursor3DIndicator.class.getName());
    /**
     * type of indicator
     */
    final private static String indicatorType = "3d cursor";
    // *************************************************************************
    // constructors

    /**
     * Instantiate an enabled control for a specified scene. After
     * instantiation, the first method invoked should be initialize().
     *
     * @param scene which scene will contain this control (not null)
     */
    public Cursor3DIndicator(SceneNode scene) {
        super(scene);
        assert isEnabled();
    }
    // *************************************************************************
    // new methods exposed

    /**
     * Get the world location of the cursor.
     *
     * @return a new vector
     */
    public Vector3f getWorldLocation() {
        Vector3f result = MySpatial.getWorldLocation(spatial);
        return result;
    }

    /**
     * Initialize this control.
     */
    public void initialize() {
        assert spatial == null : spatial;

        Geometry model = Assets.loadIndicatorModel(indicatorType);
        model.setName(indicatorType);
        /*
         * Add this control to the geometry.
         */
        model.addControl(this);
        /*
         * If this control is enabled, reveal the geometry.
         */
        if (isEnabled()) {
            scene.getIndicators().reveal(spatial);
        }
        /*
         * Position the geometry at the origin.
         */
        setWorldLocation(Vector3f.ZERO);
        /*
         * Activate this cursor by making it the POV's subject.
         */
        scene.getPov().aim(spatial);
    }

    /**
     * Move the cursor to a new location.
     *
     * @param newLocation world coordinates (not null, unaffected)
     * @return the pre-existing spatial
     */
    public Spatial setWorldLocation(Vector3f newLocation) {
        assert newLocation != null;

        MySpatial.setWorldLocation(spatial, newLocation);
        return spatial;
    }
    // *************************************************************************
    // SimpleControl methods

    /**
     * Update the cursor's color to reflect whether or not it's active. (It's
     * active when the POV orbits it.) Update its size based on its distance
     * from the POV.
     *
     * @param updateInterval time interval between updates (in seconds, &ge;0)
     */
    @Override
    public void controlUpdate(float updateInterval) {
        super.controlUpdate(updateInterval);

        PointOfView pov = scene.getPov();
        boolean isActive = pov.isOrbiting(spatial);
        Material material = Assets.createIndicatorMaterial(isActive);
        spatial.setMaterial(material);

        Vector3f povLocation = pov.getLocation();
        Vector3f cursorLocation = spatial.getWorldTranslation();
        float distance = MyVector3f.distanceFrom(povLocation, cursorLocation);
        float scale = 0.1f * distance;
        spatial.setLocalScale(scale);
    }
}